package com.example.common.downloadapk

import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.view.View
import android.widget.Toast
import com.example.common.tools.FileUtil
import com.example.common.tools.LogUtils
import com.example.common.tools.TooldUtils
import com.example.common.tools.toast
import com.example.common.widget.DownProgress
import com.zhy.base.fileprovider.FileProvider7
import io.reactivex.Observable
import io.reactivex.ObservableEmitter
import io.reactivex.ObservableOnSubscribe
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.*
import java.io.*

class DownloadUtil {

    private var downDisposable: Disposable? = null

    private var downloadLength: Long = 0
    private var contentLength: Long = 0
    private var mdfive: String? = null
    private val PERMISSIONS_STORAGE = arrayOf(
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    )

    private var MYLOG_PATH_SDCARD_DIR = TooldUtils.getDownPath() // 安装包sdcard中的路径
    private val fileName = "updateRecording.apk"

    companion object {
        private var activity: Activity? = null
        private val instance by lazy(LazyThreadSafetyMode.NONE) {
            DownloadUtil()
        }

        fun getInstance(activity: Activity): DownloadUtil {
            this.activity = activity
            return instance
        }
    }

    private constructor(){
        //判断是否可以自行创建目录
        var filePath = FileUtil.instance.isCreatePath(MYLOG_PATH_SDCARD_DIR)
        if (filePath != null){
            MYLOG_PATH_SDCARD_DIR = filePath
        }
    }

    fun down(downloadUrl: String, progressBar: DownProgress, mdfive: String) {
        this.mdfive = mdfive
        Observable.create(ObservableOnSubscribe<Int> { emitter -> downApk(downloadUrl, emitter) })
            .subscribeOn(Schedulers.io())// 将被观察者切换到子线程
            .observeOn(AndroidSchedulers.mainThread())// 将观察者切换到主线程
            .subscribe(object : Observer<Int> {
                override fun onNext(result: Int) {
                    //设置ProgressDialog 进度条进度
                    progressBar!!.setProgress(result)
                }

                override fun onSubscribe(d: Disposable) {
                    downDisposable = d
                }


                override fun onError(e: Throwable) {
                    "网络异常！请重新下载！".toast()
//                    upgrade.setEnabled(true)
                }

                override fun onComplete() {
                    "服务器异常！请重新下载！".toast()
//                    upgrade.setEnabled(true)
                }
            })
    }


    fun down(downloadUrl: String, progressBar: DownProgress) {
        Observable.create(ObservableOnSubscribe<Int> { emitter -> downApk(downloadUrl, emitter) })
            .subscribeOn(Schedulers.io())// 将被观察者切换到子线程
            .observeOn(AndroidSchedulers.mainThread())// 将观察者切换到主线程
            .subscribe(object : Observer<Int> {
                override fun onNext(result: Int) {
                    //设置ProgressDialog 进度条进度
                    progressBar!!.setProgress(result)
                }

                override fun onSubscribe(d: Disposable) {
                    downDisposable = d
                }


                override fun onError(e: Throwable) {
                    "网络异常！请重新下载！".toast()
//                    upgrade.setEnabled(true)
                }

                override fun onComplete() {
                    "服务器异常！请重新下载！".toast()
//                    upgrade.setEnabled(true)
                }
            })
    }

    /**
     * 下载app
     *
     * @param downloadUrl
     * @param emitter
     */
    private fun downApk(downloadUrl: String, emitter: ObservableEmitter<Int>) {
        LogUtils.eLog("tag", "开始下载 = $downloadUrl")
        val client = OkHttpClient()
        val request = Request.Builder()
            .url(downloadUrl)
            .build()
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                //下载失败
                breakpoint(downloadUrl, emitter)
                LogUtils.eLog("tag", "下载失败 = " + e.message)
            }

            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                if (response.body == null) {
                    //下载失败
                    breakpoint(downloadUrl, emitter)
                    LogUtils.eLog("tag", "下载失败 ")
                    return
                }
                var input: InputStream? = null
                var fos: FileOutputStream? = null
                val buff = ByteArray(2048)
                var read: Int = -1
                try {
                    input = response.body!!.byteStream()
                    val file = createFile()
                    fos = FileOutputStream(file!!)
                    val total = response.body!!.contentLength()
                    contentLength = total
                    var sum: Long = 0
                    input.use { inp ->
                        fos.use { oup ->
                            while ({ read = inp.read(buff);read }() != -1) {
                                oup.write(buff, 0, read)
                                sum += read.toLong()
                                val progress = (sum * 1.0f / total * 100).toInt()
                                //下载中，更新下载进度
                                emitter.onNext(progress)
                                downloadLength = sum
                            }
                        }
                    }
                    fos.flush()
                    //4.下载完成，安装apk
                    installApk(file)
                } catch (e: Exception) {
                    LogUtils.eLog("tag", "下载异常 = " + e.message)
                    breakpoint(downloadUrl, emitter)
                } finally {
                    try {
                        input?.close()
                        fos?.close()
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }

                }
            }
        })

    }

    //断点续传
    private fun breakpoint(downloadUrl: String, emitter: ObservableEmitter<Int>) {
        val client = OkHttpClient()
        val request = Request.Builder()
            .url(downloadUrl)
            .addHeader("RANGE", "bytes=$downloadLength-$contentLength")
            .build()
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                //下载失败
                breakpoint(downloadUrl, emitter)
            }

            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                if (response.body == null) {
                    //下载失败
                    breakpoint(downloadUrl, emitter)
                    return
                }
                var input: InputStream? = null
                var randomFile: RandomAccessFile? = null
                val buff = ByteArray(2048)
                var len: Int = -1
                try {
                    input = response.body!!.byteStream()
                    val root = Environment.getExternalStorageDirectory().path
                    val file = File(root, fileName)
                    randomFile = RandomAccessFile(file, "rwd")
                    randomFile.seek(downloadLength)
                    val total = contentLength
                    var sum = downloadLength
                    input.use { inp ->
                        randomFile.use { oup ->
                            while ({ len = inp.read(buff);len }() != -1) {
                                oup.write(buff, 0, len)
                                sum += len.toLong()
                                val progress = (sum * 1.0f / total * 100).toInt()
                                //下载中，更新下载进度
                                emitter.onNext(progress)
                                downloadLength = sum
                            }
                        }
                    }
                    //4.下载完成，安装apk
                    installApk(file)
                } catch (e: Exception) {
                    LogUtils.eLog("tag", "断点续传下载异常${e.message}")
                    breakpoint(downloadUrl, emitter)
                } finally {
                    try {
                        input?.close()
                        randomFile?.close()
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }

                }
            }
        })
    }


    private fun createFile(): File? {
        val dirsFile = File(MYLOG_PATH_SDCARD_DIR)
        if (!dirsFile.exists()) {
            dirsFile.mkdirs()
        }
        //Log.i("创建文件","创建文件");
        val file =
            File(dirsFile.toString(), fileName)// MYLOG_PATH_SDCARD_DIR
        if (!file.exists()) {
            try {
                //在指定的文件夹中创建文件
                file.createNewFile()
            } catch (e: Exception) {
            }
        }
        return file
    }

    fun installApk(file: File) {
        if (activity == null) {
            return
        }
        if (mdfive == null){
            val apkUri = FileProvider7.getUriForFile(activity, file)
            LogUtils.eLog("tag", "安装apkUri  = $apkUri")
            val intent = Intent(Intent.ACTION_VIEW)
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            //判读版本是否在7.0以上
            if (Build.VERSION.SDK_INT >= 24) {
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
            } else {
                intent.setDataAndType(
                    Uri.fromFile(file),
                    "application/vnd.android.package-archive"
                )
            }
            activity!!.startActivity(intent)
            //弹出安装窗口把原程序关闭。
            //避免安装完毕点击打开时没反应
            dispose()
            android.os.Process.killProcess(android.os.Process.myPid())
        }else {
            Observable.just(file).subscribeOn(Schedulers.io())
                .flatMap { f ->
                    val mD5 = FileUtil.instance.getMD5(file)
                    return@flatMap Observable.just(mD5)
                }.observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    //下载完成，进行MD5值比对
                    if (it == mdfive) {
                        val apkUri = FileProvider7.getUriForFile(activity, file)
                        LogUtils.eLog("tag", "安装apkUri  = $apkUri")
                        val intent = Intent(Intent.ACTION_VIEW)
                        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                        //判读版本是否在7.0以上
                        if (Build.VERSION.SDK_INT >= 24) {
                            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                            intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
                        } else {
                            intent.setDataAndType(
                                Uri.fromFile(file),
                                "application/vnd.android.package-archive"
                            )
                        }
                        activity!!.startActivity(intent)
                        //弹出安装窗口把原程序关闭。
                        //避免安装完毕点击打开时没反应
                        dispose()
                        android.os.Process.killProcess(android.os.Process.myPid())
                    } else {
                        "版本校验失败".toast()
                    }
                }, {
                    "版本校验失败".toast()
                })
        }
    }


    fun dispose() {
        downDisposable?.dispose()
    }


}

